package gmusic.appli;

import gmusic.filter.Mp3Filter;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.jaudiotagger.audio.AudioFile;
import org.jaudiotagger.audio.AudioFileIO;
import org.jaudiotagger.audio.AudioHeader;
import org.jaudiotagger.audio.exceptions.CannotReadException;
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
import org.jaudiotagger.tag.FieldKey;
import org.jaudiotagger.tag.Tag;
import org.jaudiotagger.tag.TagException;

import algutil.filter.DirectoryFilter;
import algutil.temps.Chronometre;

public class StatistiquesMp3 extends Application {

	private static final Logger log = Logger.getLogger(StatistiquesMp3.class);
	private Chronometre chrono = new Chronometre();

	private File mp3Path = null;

	private int nbMp3Parcourus = 0;
	private int nbReleasesParcourus = 0;
	private int nbMp3EnErreur = 0;
	private int nbMp3SansArtiste = 0;
	private int nbMp3SansRelease = 0;
	private int nbMp3SansTrack = 0;
	private int nbMp3SansNumero = 0;
	private int nbMp3SansDiscNumero = 0;
	private int nbMp3SansCover = 0;
	private int nbMp3SansAnnee = 0;
	private int nbMp3PasEn128br = 0;

	private List<String> releaseWithTagInvalide = new ArrayList<String>();
	private List<String> releaseWithTagInError = new ArrayList<String>();
	private List<String> releaseWithoutCover = new ArrayList<String>();
	private List<String> releaseToReEncode = new ArrayList<String>();

	public StatistiquesMp3(String[] args) throws CannotReadException,
			IOException, TagException, ReadOnlyFileException,
			InvalidAudioFrameException {
		super();
		controleArgument(args);

		java.util.logging.Logger.getLogger("org.jaudiotagger").setLevel(
				java.util.logging.Level.SEVERE);

		chrono.start();
		process(mp3Path);
		chrono.stop();

		afficherResultats();

	}

	private void afficherResultats() {

		log.info("%%% STATISTIQUES ");
		log.info("Nb de mp3/releases parcourus   : " + nbMp3Parcourus + "/"
				+ nbReleasesParcourus);
		log.info("Nb de mp3/releases en erreur   : " + nbMp3EnErreur + "/"
				+ releaseWithTagInError.size());
		log.info("Nb de mp3/releases bitrate>128 : " + nbMp3PasEn128br + "/"
				+ releaseToReEncode.size());
		log.info("Nb releases tag incomplet      : "
				+ releaseWithTagInvalide.size());
		log.info(" Nb de mp3 sans artiste        : " + nbMp3SansArtiste);
		log.info(" Nb de mp3 sans release        : " + nbMp3SansRelease);
		log.info(" Nb de mp3 sans annee          : " + nbMp3SansAnnee);
		log.info(" Nb de mp3 sans disc number    : " + nbMp3SansDiscNumero);
		log.info(" Nb de mp3 sans track          : " + nbMp3SansTrack);
		log.info(" Nb de mp3 sans track number   : " + nbMp3SansNumero);
		log.info("Nb de mp3/releases sans cover : " + nbMp3SansCover + "/"
				+ releaseWithoutCover.size());
		log.info("Tps de traitement              : " + chrono.getDuree());
		log.info("Tps de traitement moy/track    : "
				+ Chronometre.getDuree4Display(chrono.getTempsEcouleMS()
						/ nbMp3Parcourus));
		log.info("Tps de traitement moy/release  : "
				+ Chronometre.getDuree4Display(chrono.getTempsEcouleMS()
						/ nbReleasesParcourus));
		log
				.info("# Liste des releases avec tag invalide (absence de disc number ignore)");
		for (int i = 0; i < releaseWithTagInvalide.size(); i++) {
			log.info(releaseWithTagInvalide.get(i));
		}
		log.info("# Liste des releases avec tag en erreur");
		for (int i = 0; i < releaseWithTagInError.size(); i++) {
			log.info(releaseWithTagInError.get(i));
		}
		log.info("# Liste des releases a re-encoder");
		for (int i = 0; i < releaseToReEncode.size(); i++) {
			log.info(releaseToReEncode.get(i));
		}
		log.info("# Liste des releases sans cover");
		for (int i = 0; i < releaseWithoutCover.size(); i++) {
			log.info(releaseWithoutCover.get(i));
		}
	}

	@Override
	protected boolean controleArgument(String[] args) {
		if (args.length != 1) {
			afficherMessageErrorEtUsageEtExit("Nombre d'arguments invalide");
		} else {
			mp3Path = new File(args[0]);
			controleRepertoire(mp3Path);
		}
		return true;
	}

	public static void main(String[] args) throws CannotReadException,
			IOException, TagException, ReadOnlyFileException,
			InvalidAudioFrameException {
		new StatistiquesMp3(args);
	}

	@Override
	protected void afficherUsage() {
		log.error("Usage : gmusic.appli.StatistiquesMp3 <repertoire_mp3>");
	}

	private void process(File mp3Path) throws CannotReadException, IOException,
			TagException, ReadOnlyFileException, InvalidAudioFrameException {
		File[] mp3s = mp3Path.listFiles(new Mp3Filter());
		for (int i = 0; i < mp3s.length; i++) {
			checkMp3File(mp3s[i]);
		}

		File[] sousRep = mp3Path.listFiles(new DirectoryFilter());
		for (int i = 0; i < sousRep.length; i++) {
			if (sousRep[i].getName().startsWith("A")) {
				process(sousRep[i]);
				nbReleasesParcourus++;
			}
		}
	}

	private void checkMp3File(File mp3) {
		nbMp3Parcourus++;

		try {
			AudioFile f = AudioFileIO.read(mp3);

			AudioHeader ah = f.getAudioHeader();
			if (ah.getBitRateAsNumber() > 128) {
				nbMp3PasEn128br++;
				addReleaseToRealeaseToReEncode(mp3.getParentFile().getName());
			}

			Tag tag = f.getTag();
			if (tag.getFirst(FieldKey.ARTIST).length() == 0) {
				nbMp3SansArtiste++;
				addReleaseToRealeaseWithTagInvalide(mp3.getParentFile()
						.getName());
			}
			if (tag.getFirst(FieldKey.ALBUM).length() == 0) {
				nbMp3SansRelease++;
				addReleaseToRealeaseWithTagInvalide(mp3.getParentFile()
						.getName());
			}
			if (tag.getFirst(FieldKey.TITLE).length() == 0) {
				nbMp3SansTrack++;
				addReleaseToRealeaseWithTagInvalide(mp3.getParentFile()
						.getName());
			}
			if (tag.getFirst(FieldKey.YEAR).length() == 0) {
				nbMp3SansAnnee++;
				addReleaseToRealeaseWithTagInvalide(mp3.getParentFile()
						.getName());
			}
			if (tag.getFirst(FieldKey.TRACK).length() == 0) {
				nbMp3SansNumero++;
				addReleaseToRealeaseWithTagInvalide(mp3.getParentFile()
						.getName());
			}
			if (tag.getFirst(FieldKey.DISC_NO).length() == 0) {
				nbMp3SansDiscNumero++;
				// addReleaseToRealeaseWithTagInvalide(mp3.getParentFile().getName());
			}
			if (tag.getFirstField(FieldKey.COVER_ART) == null) {
				nbMp3SansCover++;
				addReleaseToRealeaseWithoutCover(mp3.getParentFile().getName());
			}
		} catch (Exception e) {
			nbMp3EnErreur++;
			addReleaseToRealeaseWithTagInError(mp3.getParentFile().getName());
		}

	}

	private void addReleaseToRealeaseWithoutCover(String release) {

		boolean alreadyExists = false;
		for (int i = releaseWithoutCover.size() - 1; i >= 0; i--) {
			if (releaseWithoutCover.get(i).equalsIgnoreCase(release)) {
				alreadyExists = true;
				break;
			}
		}
		if (!alreadyExists) {
			releaseWithoutCover.add(release);
		}
	}

	private void addReleaseToRealeaseWithTagInError(String release) {

		boolean alreadyExists = false;
		for (int i = releaseWithTagInError.size() - 1; i >= 0; i--) {
			if (releaseWithTagInError.get(i).equalsIgnoreCase(release)) {
				alreadyExists = true;
				break;
			}
		}
		if (!alreadyExists) {
			releaseWithTagInError.add(release);
		}
	}

	private void addReleaseToRealeaseWithTagInvalide(String release) {

		boolean alreadyExists = false;
		for (int i = releaseWithTagInvalide.size() - 1; i >= 0; i--) {
			if (releaseWithTagInvalide.get(i).equalsIgnoreCase(release)) {
				alreadyExists = true;
				break;
			}
		}
		if (!alreadyExists) {
			releaseWithTagInvalide.add(release);
		}
	}

	private void addReleaseToRealeaseToReEncode(String release) {

		boolean alreadyExists = false;
		for (int i = releaseToReEncode.size() - 1; i >= 0; i--) {
			if (releaseToReEncode.get(i).equalsIgnoreCase(release)) {
				alreadyExists = true;
				break;
			}
		}
		if (!alreadyExists) {
			releaseToReEncode.add(release);
		}
	}
}
